feat: install plugins to auto-load across sessions (#36) - #227
Merged
Conversation
Add `!plugin install <file>`, which loads a plugin and records its name in a
persistent manifest (`<config_dir>/scope/plugins/installed.toml`) so every
subsequent session auto-loads it at start-up; `!plugin list` prints the
installed set.
A new `plugin/installed.rs` owns the manifest (load/add/save, dir-injected and
unit-tested); it is program-managed state, so a missing manifest is simply
"nothing installed" and a malformed one is logged and skipped rather than
bricking the app. The engine grows `PluginEngineCommand::{InstallPlugin,
ListInstalledPlugins}`: install stages+loads the plugin and persists it only
after a successful load (a broken plugin is never recorded), deduping so
re-installs are idempotent. `load_installed_plugins` runs once at the top of
`task_async`, before the command loop, auto-loading each installed plugin from
its staged copy and logging per plugin like `!plugin load`. The `!plugin`
command handler is refactored to a subcommand-first shape so `list` needs no
argument while load/reload/install/unload each take one.
Uninstall is issue #37.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Closes #36. Adds
!plugin install <file>: it loads the plugin and records it so every subsequentScopesession auto-loads it at start-up — no more re-running!plugin loadfor your everyday plugins.!plugin listprints the installed set.How
src/plugin/installed.rs(new) — the manifestInstalledover<config_dir>/scope/plugins/installed.toml(plugins = ["name", …]), next to the staged.luafiles.load/names/contains/add(dedup) /save, dir-injected and unit-tested. It is program-managed state (not the user'sconfig.toml): a missing manifest means "nothing installed", and a malformed one is logged and skipped so it can never brick start-up.src/plugin/engine.rs—PluginEngineCommand::{InstallPlugin, ListInstalledPlugins}. Install stages + loads the plugin and persists only after a successful load (a plugin that fails to load is never added to the auto-load set), deduping so re-installs are idempotent.load_installed_pluginsruns once at the top oftask_async, before the command loop, auto-loading each installed plugin from its staged copy and logging per plugin like!plugin load; a broken/missing entry is logged and skipped.src/inputs/inputs_task.rs— the!pluginhandler is refactored to a subcommand-first shape solistneeds no argument whileload/reload/install/unloadeach take one; the existingload/reload/unloadbehavior is preserved.plugins/README.md, CLAUDE.md.Uninstall is deliberately out of scope — it is issue #37. The manifest already supports removal for that follow-up.
Tests
installed.rsunit tests: missing / malformed / round-trip / dedup / dir-creation.tests/tui_e2e.rs(harness gained aStartOptsbuilder + aplugins_dir()accessor):!plugin listreports the empty and populated sets;scope/shell) is rejected and not persisted.The last four were added from an adversarial review of the diff, which found no logic defects — only these coverage gaps on the safety paths.
All 231 unit + 20 e2e tests pass (1 e2e ignored on macOS per the existing PTY-baud limitation); tree is warning-clean under
#![deny(warnings)].🤖 Generated with Claude Code